﻿using CasignDesignGA.Casign;
using CasignDesignGA.Casing;
using CasignDesingGA.Casing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CasignDesignGA.Engine.Population
{
    class Population
    {
        private List<ISelectable> individuals;
       
        private double averageAptitude = 0;

        public double AverageAptitude
        {
            get { return averageAptitude; }
            set { averageAptitude = value; }
        }
        private double bestAptitude = 0;

        public double BestAptitude
        {
            get { return bestAptitude; }
            set { bestAptitude = value; }
        }
        private double worstAptitude = 0;

        public double WorstAptitude
        {
            get { return worstAptitude; }
            set { worstAptitude = value; }
        }

        internal List<ISelectable> Individuals
        {
            get { return individuals; }
            set { individuals = value; }
        }

        public Population()
        {
            this.individuals = new List<ISelectable>();
        }

        public void Add(Population newChilds)
        {
            foreach (CasingDesign item in newChilds.Individuals)
            {
                this.individuals.Add(item);
            }
            
        }

        public ISelectable getIndividualIndex(int index)
        {
            if (index >= 0 && index < this.individuals.Count)
            {
                return this.individuals[index];
            }
            return null;
        }
        public List<ISelectable> convertToSortedList()
        {
            

            this.individuals.Sort(delegate(ISelectable p1, ISelectable p2)
            {
                return ((CasingDesign)p2).Aptitude.CompareTo(((CasingDesign)p1).Aptitude);
            });
              return this.individuals;
        }
        public int count()
        {
            return individuals.Count;
        }

        public void Add(ISelectable aChild)
        {
            this.individuals.Add(aChild);
        }

        public void AgePopulation(int lifeCycle)
        {
            List<ISelectable> aboutToDieList = new List<ISelectable>();
            foreach (CasingDesign aCasing in this.individuals)
            {
                aCasing.LifeCycle++;
                if (aCasing.LifeCycle > lifeCycle)
                {
                    /*Kill this individual*/
                    aboutToDieList.Add(aCasing);
                }
            }

            foreach (CasingDesign aCasing in aboutToDieList)
            {
                this.individuals.Remove(aCasing);
            }
            aboutToDieList.Clear();
            
        }

        public void ReCalculateAptitude(double designFactor)
        {
            this.averageAptitude = 0;
            foreach (CasingDesign aCasing in this.individuals)
            {
                aCasing.calculateAptitude(designFactor);
                this.averageAptitude += aCasing.Aptitude / this.count();
            }
            this.BestAptitude = ((CasingDesign)this.convertToSortedList().First()).Aptitude;
            this.WorstAptitude = ((CasingDesign)this.convertToSortedList().Last()).Aptitude;
        }

        public string BestIndividualDescription()
        {
            CasingDesign bestIndividual = (CasingDesign)this.convertToSortedList().First();

            
            return bestIndividual.ToString();
        }

        public string WorstIndividualDescription()
        {
            CasingDesign worstIndividual = (CasingDesign)this.convertToSortedList().Last();
            return worstIndividual.ToString();
        }


        public CasingDesign getBestIndividual()
        {
            return  (CasingDesign)this.convertToSortedList().First();
        }

        internal CasingProperty getBestIndividualCollapse()
        {
            CasingDesign bestIndividual = (CasingDesign)this.convertToSortedList().First();
            CasingProperty collapseProperty = new CasingProperty();
            collapseProperty.Add(0, firstCasingCollapse(bestIndividual));
            foreach (CasingUnit unit in bestIndividual.CasingCollection)
            {
                collapseProperty.Add(unit.Longitude, unit.Collapse);
            }
            collapseProperty.Add(Well.Well.Instance.Depth, lastCasingCollapse(bestIndividual));
            return collapseProperty;
        }

        private double lastCasingCollapse(CasingDesign bestIndividual)
        {
            return bestIndividual.CasingCollection[1].Collapse;
        }

        private double firstCasingCollapse(CasingDesign bestIndividual)
        {
            return bestIndividual.CasingCollection[0].Collapse;
        }

        internal CasingProperty getBestIndividualBurst()
        {
            CasingDesign bestIndividual = this.getBestIndividual();
            CasingProperty burstProperty = new CasingProperty();
            burstProperty.Add(0, firstCasingBurst(bestIndividual));
            foreach (CasingUnit unit in bestIndividual.CasingCollection)
            {
                burstProperty.Add(unit.Longitude, unit.Burst);
            }
            burstProperty.Add(Well.Well.Instance.Depth, lastCasingBurst(bestIndividual));
            return burstProperty;
        }

        private double lastCasingBurst(CasingDesign bestIndividual)
        {
            return bestIndividual.CasingCollection[1].Burst;
        }

        private double firstCasingBurst(CasingDesign bestIndividual)
        {
            return bestIndividual.CasingCollection[0].Burst;
        }
    }
}
